package cn.netty.exemple2;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;


/**
 * <p>Title: TimeServer</p>
 * <p>Description: 解决粘包问题</p>
 * @version V1.0
 * @author ZhiPeng_Chen
 * @date: 2018/10/31
 */
public class TimeServer {

    private NioEventLoopGroup acceptorGroup;
    private NioEventLoopGroup workGroup;

    private ServerBootstrap serverBootstrap;

    public TimeServer(){
       init();
    }


    public void init(){
        this.acceptorGroup= new NioEventLoopGroup();
        this.workGroup= new NioEventLoopGroup();
        this.serverBootstrap = new ServerBootstrap();
        this.serverBootstrap.group(acceptorGroup,workGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,1024);
    }


    /**
     * LineBasedFrameDecoder 的工作原理是依次遍历BuyBuf中的可读字节
     * 判断是否有"/n"或者"\r\n"如果有有就作为结束位置
     *
     * StringDeconde的功能也非常简单，就是将接收到的对象装换成字符串
     * 然后继续调用后面的handler
     * LineBasedFrameDecoder + StringDeconde的功能也非常简单 = 用于设计解决粘包的问题
     *
     * @param port
     * @return
     * @throws InterruptedException
     */
    public ChannelFuture doAccept(int port) throws InterruptedException {

        this.serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline()
                        //解决粘包问题 Handler放在执行链最下面
                        .addLast(new LineBasedFrameDecoder(1024))
                        .addLast(new StringDecoder())
                        .addLast(new TimeServerHandler());
            }
        });
        ChannelFuture future = this.serverBootstrap.bind(port).sync();
        return future;
    }

    public void shutDown(){
        workGroup.shutdownGracefully();
        acceptorGroup.shutdownGracefully();
    }

    public static void main(String[] args) {
        TimeServer server = new TimeServer();
        ChannelFuture future = null;
        try {
             future = server.doAccept(8888);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            server.shutDown();
        }

    }
}
